package devops.katas.adminconsumer;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;

@SpringBootApplication
public class AdminConsumerApplication {

	public static void main(String[] args) {
		SpringApplication.run(AdminConsumerApplication.class, args);
	}

}

class Admin {
	private String firstName;
	private String lastName;

	// Need to have the default constructor to fix issue "InvalidDefinitionException: Cannot construct instance of
	// `devops.katas.adminconsumer.Admin` (no Creators, like default constructor, exist): cannot deserialize from
	// Object value (no delegate- or property-based Creator)"
	public Admin() {
	}

	// Need to have fields and getters to fix issue "InvalidDefinitionException: No serializer found
	// no properties discovered to create BeanSerializer"
	public Admin(String firstName, String lastName) {
		this.firstName = firstName;
		this.lastName = lastName;
	}

	public String getFirstName() {
		return firstName;
	}

	public String getLastName() {
		return lastName;
	}
}

interface AdminRetriever {

	Admin admin(int id);
}

class HttpAdminRetriever implements AdminRetriever {
	private final RestTemplate restTemplate;
	private final String serverUrl;

	public HttpAdminRetriever(RestTemplate restTemplate, String serverUrl) {
		this.restTemplate = restTemplate;
		this.serverUrl = serverUrl;
	}

	@Override
	public Admin admin(int id) {
		return this.restTemplate.getForObject("http://" + this.serverUrl + "/admin/{id}",
				Admin.class, id);
	}
}

class AdminService {

	private AdminRetriever adminRetriever;

	public AdminService(AdminRetriever adminRetriever) {
		this.adminRetriever = adminRetriever;
	}

	public List<Admin> admins() {
		List<Admin> admins = new ArrayList<>();
		admins.add(this.adminRetriever.admin(1));
		admins.add(this.adminRetriever.admin(2));
		return admins;
	}
}

@Configuration
class AdminConfiguration {
	@Bean
	RestTemplate restTemplate() {
		return new RestTemplate();
	}

	@Bean
	AdminRetriever adminRetriever(@Value("${admin.server.url:localhost}") String serverUrl,
								  @Value("${admin.server.port:8765}") int serverPort) {
		return new HttpAdminRetriever(restTemplate(), serverUrl + ":" + serverPort);
	}

	@Bean
	AdminService adminService(AdminRetriever adminRetriever) {
		return new AdminService(adminRetriever);
	}

}

@RestController
class AdminController {

	private AdminService adminService;

	public AdminController(AdminService adminService) {
		this.adminService = adminService;
	}

	@GetMapping("/admins")
	List<Admin> admins() {
		return this.adminService.admins();
	}
}